1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkState;
21 import static com.google.common.collect.CollectPreconditions.checkRemove;
22
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.annotations.GwtIncompatible;
25 import com.google.common.base.Objects;
26
27 import java.io.IOException;
28 import java.io.ObjectInputStream;
29 import java.io.ObjectOutputStream;
30 import java.io.Serializable;
31 import java.util.Collection;
32 import java.util.Iterator;
33 import java.util.Map;
34 import java.util.Set;
35
36 import javax.annotation.Nullable;
37
38
39
40
41
42
43
44
45
46
47
48 @GwtCompatible(emulated = true)
49 abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
50 implements BiMap<K, V>, Serializable {
51
52 private transient Map<K, V> delegate;
53 transient AbstractBiMap<V, K> inverse;
54
55
56 AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
57 setDelegates(forward, backward);
58 }
59
60
61 private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
62 delegate = backward;
63 inverse = forward;
64 }
65
66 @Override protected Map<K, V> delegate() {
67 return delegate;
68 }
69
70
71
72
73 K checkKey(@Nullable K key) {
74 return key;
75 }
76
77
78
79
80 V checkValue(@Nullable V value) {
81 return value;
82 }
83
84
85
86
87
88 void setDelegates(Map<K, V> forward, Map<V, K> backward) {
89 checkState(delegate == null);
90 checkState(inverse == null);
91 checkArgument(forward.isEmpty());
92 checkArgument(backward.isEmpty());
93 checkArgument(forward != backward);
94 delegate = forward;
95 inverse = new Inverse<V, K>(backward, this);
96 }
97
98 void setInverse(AbstractBiMap<V, K> inverse) {
99 this.inverse = inverse;
100 }
101
102
103
104 @Override public boolean containsValue(@Nullable Object value) {
105 return inverse.containsKey(value);
106 }
107
108
109
110 @Override public V put(@Nullable K key, @Nullable V value) {
111 return putInBothMaps(key, value, false);
112 }
113
114 @Override
115 public V forcePut(@Nullable K key, @Nullable V value) {
116 return putInBothMaps(key, value, true);
117 }
118
119 private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
120 checkKey(key);
121 checkValue(value);
122 boolean containedKey = containsKey(key);
123 if (containedKey && Objects.equal(value, get(key))) {
124 return value;
125 }
126 if (force) {
127 inverse().remove(value);
128 } else {
129 checkArgument(!containsValue(value), "value already present: %s", value);
130 }
131 V oldValue = delegate.put(key, value);
132 updateInverseMap(key, containedKey, oldValue, value);
133 return oldValue;
134 }
135
136 private void updateInverseMap(
137 K key, boolean containedKey, V oldValue, V newValue) {
138 if (containedKey) {
139 removeFromInverseMap(oldValue);
140 }
141 inverse.delegate.put(newValue, key);
142 }
143
144 @Override public V remove(@Nullable Object key) {
145 return containsKey(key) ? removeFromBothMaps(key) : null;
146 }
147
148 private V removeFromBothMaps(Object key) {
149 V oldValue = delegate.remove(key);
150 removeFromInverseMap(oldValue);
151 return oldValue;
152 }
153
154 private void removeFromInverseMap(V oldValue) {
155 inverse.delegate.remove(oldValue);
156 }
157
158
159
160 @Override public void putAll(Map<? extends K, ? extends V> map) {
161 for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
162 put(entry.getKey(), entry.getValue());
163 }
164 }
165
166 @Override public void clear() {
167 delegate.clear();
168 inverse.delegate.clear();
169 }
170
171
172
173 @Override
174 public BiMap<V, K> inverse() {
175 return inverse;
176 }
177
178 private transient Set<K> keySet;
179
180 @Override public Set<K> keySet() {
181 Set<K> result = keySet;
182 return (result == null) ? keySet = new KeySet() : result;
183 }
184
185 private class KeySet extends ForwardingSet<K> {
186 @Override protected Set<K> delegate() {
187 return delegate.keySet();
188 }
189
190 @Override public void clear() {
191 AbstractBiMap.this.clear();
192 }
193
194 @Override public boolean remove(Object key) {
195 if (!contains(key)) {
196 return false;
197 }
198 removeFromBothMaps(key);
199 return true;
200 }
201
202 @Override public boolean removeAll(Collection<?> keysToRemove) {
203 return standardRemoveAll(keysToRemove);
204 }
205
206 @Override public boolean retainAll(Collection<?> keysToRetain) {
207 return standardRetainAll(keysToRetain);
208 }
209
210 @Override public Iterator<K> iterator() {
211 return Maps.keyIterator(entrySet().iterator());
212 }
213 }
214
215 private transient Set<V> valueSet;
216
217 @Override public Set<V> values() {
218
219
220
221
222 Set<V> result = valueSet;
223 return (result == null) ? valueSet = new ValueSet() : result;
224 }
225
226 private class ValueSet extends ForwardingSet<V> {
227 final Set<V> valuesDelegate = inverse.keySet();
228
229 @Override protected Set<V> delegate() {
230 return valuesDelegate;
231 }
232
233 @Override public Iterator<V> iterator() {
234 return Maps.valueIterator(entrySet().iterator());
235 }
236
237 @Override public Object[] toArray() {
238 return standardToArray();
239 }
240
241 @Override public <T> T[] toArray(T[] array) {
242 return standardToArray(array);
243 }
244
245 @Override public String toString() {
246 return standardToString();
247 }
248 }
249
250 private transient Set<Entry<K, V>> entrySet;
251
252 @Override public Set<Entry<K, V>> entrySet() {
253 Set<Entry<K, V>> result = entrySet;
254 return (result == null) ? entrySet = new EntrySet() : result;
255 }
256
257 private class EntrySet extends ForwardingSet<Entry<K, V>> {
258 final Set<Entry<K, V>> esDelegate = delegate.entrySet();
259
260 @Override protected Set<Entry<K, V>> delegate() {
261 return esDelegate;
262 }
263
264 @Override public void clear() {
265 AbstractBiMap.this.clear();
266 }
267
268 @Override public boolean remove(Object object) {
269 if (!esDelegate.contains(object)) {
270 return false;
271 }
272
273
274 Entry<?, ?> entry = (Entry<?, ?>) object;
275 inverse.delegate.remove(entry.getValue());
276
277
278
279
280
281 esDelegate.remove(entry);
282 return true;
283 }
284
285 @Override public Iterator<Entry<K, V>> iterator() {
286 final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
287 return new Iterator<Entry<K, V>>() {
288 Entry<K, V> entry;
289
290 @Override public boolean hasNext() {
291 return iterator.hasNext();
292 }
293
294 @Override public Entry<K, V> next() {
295 entry = iterator.next();
296 final Entry<K, V> finalEntry = entry;
297
298 return new ForwardingMapEntry<K, V>() {
299 @Override protected Entry<K, V> delegate() {
300 return finalEntry;
301 }
302
303 @Override public V setValue(V value) {
304
305 checkState(contains(this), "entry no longer in map");
306
307 if (Objects.equal(value, getValue())) {
308 return value;
309 }
310 checkArgument(!containsValue(value),
311 "value already present: %s", value);
312 V oldValue = finalEntry.setValue(value);
313 checkState(Objects.equal(value, get(getKey())),
314 "entry no longer in map");
315 updateInverseMap(getKey(), true, oldValue, value);
316 return oldValue;
317 }
318 };
319 }
320
321 @Override public void remove() {
322 checkRemove(entry != null);
323 V value = entry.getValue();
324 iterator.remove();
325 removeFromInverseMap(value);
326 }
327 };
328 }
329
330
331
332 @Override public Object[] toArray() {
333 return standardToArray();
334 }
335 @Override public <T> T[] toArray(T[] array) {
336 return standardToArray(array);
337 }
338 @Override public boolean contains(Object o) {
339 return Maps.containsEntryImpl(delegate(), o);
340 }
341 @Override public boolean containsAll(Collection<?> c) {
342 return standardContainsAll(c);
343 }
344 @Override public boolean removeAll(Collection<?> c) {
345 return standardRemoveAll(c);
346 }
347 @Override public boolean retainAll(Collection<?> c) {
348 return standardRetainAll(c);
349 }
350 }
351
352
353 private static class Inverse<K, V> extends AbstractBiMap<K, V> {
354 private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
355 super(backward, forward);
356 }
357
358
359
360
361
362
363
364
365
366
367 @Override
368 K checkKey(K key) {
369 return inverse.checkValue(key);
370 }
371
372 @Override
373 V checkValue(V value) {
374 return inverse.checkKey(value);
375 }
376
377
378
379
380 @GwtIncompatible("java.io.ObjectOuputStream")
381 private void writeObject(ObjectOutputStream stream) throws IOException {
382 stream.defaultWriteObject();
383 stream.writeObject(inverse());
384 }
385
386 @GwtIncompatible("java.io.ObjectInputStream")
387 @SuppressWarnings("unchecked")
388 private void readObject(ObjectInputStream stream)
389 throws IOException, ClassNotFoundException {
390 stream.defaultReadObject();
391 setInverse((AbstractBiMap<V, K>) stream.readObject());
392 }
393
394 @GwtIncompatible("Not needed in the emulated source.")
395 Object readResolve() {
396 return inverse().inverse();
397 }
398
399 @GwtIncompatible("Not needed in emulated source.")
400 private static final long serialVersionUID = 0;
401 }
402
403 @GwtIncompatible("Not needed in emulated source.")
404 private static final long serialVersionUID = 0;
405 }